//ref pointer
//$Id: ref_ptr.h 395 2010-03-26 14:01:03Z Oleg.Bulychov $
#pragma once

#include <limits>

#include "src/heo/include/reflection.h"
#include "src/heo/include/stream_visitor.h"
//__________________________________________________________________________________
//__________________________________________________________________________________
//__________________________________________________________________________________
template<typename T>
class ref_ptr
{
protected:
    T* p_;
public:

    ref_ptr(T* p = NULL) NO_THROW_(): p_(p)
    {
        if (p)
        {
            p->add_Ref();
        }
    }

    ref_ptr(ref_ptr const& right) NO_THROW_(): p_(right.p_)
    {
        if (p_)
        {
            p_->add_Ref();
        }
    }

    ref_ptr& operator=(ref_ptr const& right) NO_THROW_()
    {
        if (right.p_)
            right.p_->add_Ref();
        if (p_)
            p_->release();
        p_ = right.p_;
        return *this;
    }

    ~ref_ptr() NO_THROW_()
    {
        if (p_)
            p_->release();
    }

    void clear() NO_THROW_()
    {
        T* tmp = p_;
        if (tmp)
        {
            p_ = NULL;
            tmp->release();
        }
    }

    void attach(T* p) NO_THROW_()
    {
        if (p_)
            p_->release();
        p_ = p;
    }

    T* detach() NO_THROW_()
    {
        T* p = p_;
        p_ = NULL;
        return p;
    }

    void swap(ref_ptr& right) NO_THROW_()
    {
        T* tmp(right.p_);
        right.p_ = p_;
        p_ = tmp;
    }

    T* operator->() const NO_THROW_()
    {
        ASSERT_(p_ != NULL);
        return p_;
    }

    operator T*() const NO_THROW_()
    {
        return p_;
    }

    T& operator*() const NO_THROW_()
    {
        ASSERT_(p_ != NULL);
        return *p_;
    }

    T* in() const NO_THROW_()
    {
        ASSERT_(p_ != NULL);
        return p_;
    }

    T** out() const NO_THROW_()
    {
        ASSERT_(!p_);
        return &p_;
    }
};
//__________________________________________________________________________________
//__________________________________________________________________________________
//__________________________________________________________________________________
//__________________________________________________________________________________
class ref_object
{
    long ref_count_;
public:
    ref_object() NO_THROW_(): ref_count_(1)
    {}

    virtual ~ref_object() NO_THROW_()
    {}

    virtual void add_Ref() NO_THROW_()
    {
        ++ref_count_;
    }

    virtual void release() NO_THROW_()
    {
        long r = --ref_count_;
        //:Stop if release called on a pointer that has already been released
        ASSERT_(r >= -(std::numeric_limits<long>::max() / 2));
        if (!r)
        {
#if defined(_DEBUG)
            ref_count_ = -(std::numeric_limits<long>::max() / 2);
#endif
            //:This enables you to safely access the methods provided by the most derived class
            //:pre_Destructor();

            delete this;//:virtual
        }
    }
};
//__________________________________________________________________________________
//__________________________________________________________________________________
//__________________________________________________________________________________
//__________________________________________________________________________________
namespace meta
{
//__________________________________________________________________________________
template<class T>
struct is_visitable< ref_ptr<T> >
{
    enum {result = 0};
};
//__________________________________________________________________________________
template<typename T, class D>
struct simple_validator<ref_ptr<T>, D>
{
    static void set_Default(ref_ptr<T>& pt, D const& d)
    {
        pt.clear();
    }
};
//__________________________________________________________________________________
//__________________________________________________________________________________
template<class T>
struct reflection_handler< ref_ptr<T>, meta::ostream_visitor>
{
    template<class D>
    static void visit(ref_ptr<T>& pt, char const* szName, D const&, meta::ostream_visitor& v)
    {
        if (*szName)
        {
            v.out_ << v.padd_.c_str() << "*" << szName << " = {" << lf;
            v.padd_.resize(v.padd_.length() + 2, ' ');
        }
        if (!pt)
        {
            v.out_ << v.padd_.c_str() << "NULL" << lf;
        }
        else
        {
            Dispatch_Visit(v, pt.in(), "");
        }
        if (*szName)
        {
            v.padd_.resize(v.padd_.length() - 2);
            v.out_ << v.padd_.c_str() << "}" << lf;
        }
    }
};
//__________________________________________________________________________________
}
//__________________________________________________________________________________
//__________________________________________________________________________________
//__________________________________________________________________________________

//EOF!
